home *** CD-ROM | disk | FTP | other *** search
/ Die Ultimative Software-P…i Collection 1996 & 1997 / Die Ultimative Software-Pakete CD-ROM fur Atari Collection 1996 & 1997.iso / i / internet / software / tuwtcpsr / udp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-19  |  8.8 KB  |  300 lines

  1. #include <stdlib.h>
  2. #include <time.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <tos.h>
  6. #include "pktdrv.h"
  7. #include "ip.h"
  8. #include "icmp.h"
  9. #include "timer.h"
  10. #include "udp.h"
  11. #include "inetcust.h"
  12. #include "mbuf.h"
  13.  
  14. #include "nettrace.h"
  15.  
  16. #define Bconws(x) dpy = x;while(*dpy)(Bconout(2,*dpy++))
  17.  
  18. static char *dpy;
  19.  
  20. #define noDEBUGDROP
  21. #define noDEBUGRECV
  22. #define noDEBUGOPN
  23. #define noDEBUGCLS
  24. #define noDEBUGWR
  25.  
  26. #define min(a,b) ((a) < (b) ? (a) : (b))
  27.  
  28. UDP_CTL  *udp_list = NULL;
  29. UDP_CTL **udp_tab;
  30. int          udp_tablen = 0;
  31. extern char *udp_buffers;
  32. int udp_handler(PACKET *,int,INADDR);
  33. int udp_du_handler(IP *);
  34. void udp_droppacket(TIMER);
  35. u_short udp_newport(void);long udp_counts[2] = {0,0};
  36.  
  37. int udp_init(void)
  38. {
  39. register int i;
  40.     udp_list = NULL;
  41.     udp_tablen = UDP_MAXPORTS;
  42.     udp_tab = (UDP_CTL **)getmem((size_t)udp_tablen*sizeof(UDP_CTL *));
  43.     if(!udp_tab) return(FALSE);
  44.     for(i=0; i<udp_tablen; i++)
  45.         udp_tab[i] = NULL;
  46.     if(!ip_open(IP_UDP,udp_handler,udp_du_handler))
  47.     {
  48.         freemem(udp_tab);
  49.         return(FALSE);
  50.     }
  51.     return(TRUE);
  52. }
  53.  
  54. int udp_exit(void)
  55. {
  56. int i;
  57.  
  58.     if(udp_tab)
  59.     {
  60.         for(i=0;i<udp_tablen;i++)
  61.             if(udp_tab[i]) udp_close(i);
  62.         free(udp_tab);
  63.         udp_tab = NULL;
  64.         udp_tablen = 0;
  65.     }
  66.     return(ip_close(IP_UDP));
  67. }
  68.  
  69.  
  70. int udp_handler(PACKET *pkt,int len,INADDR fhost){
  71. UDP_CTL *p_udpctl;IP         *p_ip;register UDP *p_udp;
  72. TCP_PSEUDO tcp_ph;u_short csum;unsigned plen;
  73.     /* First let's verify that it's a valid UDP packet. */    p_ip = ip_head(pkt);    p_udp = udp_head(p_ip);
  74.     
  75.     plen = p_udp->length;    if(plen > len)
  76.     {
  77. #ifdef DEBUGRECV
  78. printf("invalid packet %u,%u\n",plen,len);
  79. #endif        ip_free(pkt);        return(FALSE);    }    csum = p_udp->chksum;    if(csum)
  80.     {        tcp_ph.src = fhost;        tcp_ph.dst = p_ip->dst_inaddr;        tcp_ph.protocol = IP_UDP;        tcp_ph.length  = len;        p_udp->chksum = ~chksum((u_short *)&tcp_ph,(u_short)sizeof(TCP_PSEUDO),0);        p_udp->chksum = chksum((u_short *)p_udp,len,0);
  81.         if(csum != p_udp->chksum && !(csum == 0xffff && p_udp->chksum == 0))
  82.         {
  83. #ifdef DEBUGRECV
  84. printf("bad checksum %04x->%04x\n",csum,p_udp->chksum);
  85. #endif            ip_free(pkt);            return(FALSE);        }
  86.     }    /* ok, accept it. run through the demux table and try to upcall it */    for(p_udpctl = udp_list; p_udpctl; p_udpctl = p_udpctl->next)
  87.     {        if(p_udpctl->lcl_port && (p_udpctl->lcl_port != p_udp->dst_port))            continue;
  88.         if(p_udpctl->upcall)
  89.         {
  90. #ifdef DEBUGRECV
  91. printf("pkt [%d] from %8lx.%u to port %u\n",len,fhost,p_udp->src_port,p_udpctl->lcl_port);
  92. #endif            p_udpctl->fhost = fhost;
  93.             p_udpctl->fgn_port = p_udp->src_port;
  94.             p_udpctl->data_len = len - sizeof(UDP);
  95.             p_udpctl->data = (char *)p_udp+sizeof(UDP);
  96.             if(p_udpctl->pkt)
  97.             {
  98. #ifdef DEBUGRECV
  99. printf("packet overrun\n");
  100. #endif
  101.                 ip_free(p_udpctl->pkt);            /* throw away old packet */
  102.                 p_udpctl->udp_err = UDP_OVR;    /* signal overrun */
  103.             }
  104.             else
  105.                 p_udpctl->udp_err = UDP_OK;
  106.             p_udpctl->pkt = NULL;
  107.                 ip_free(pkt);            /* throw away old packet */
  108.             udp_counts[0]++;            tm_stop(p_udpctl->udp_tm);
  109.             tm_set(UDP_KEEPPKT,udp_droppacket,p_udpctl->udp_tm);            (p_udpctl->upcall)(p_udpctl->handle,(char *)p_udp+sizeof(UDP), len-(int)sizeof(UDP));
  110.         }
  111.         else
  112.         {
  113.             p_udpctl->fhost = 0L;
  114.             p_udpctl->fgn_port = 0;
  115.             p_udpctl->data_len = 0;
  116.             p_udpctl->data = NULL;
  117.             p_udpctl->pkt = NULL;            ip_free(pkt);
  118.         }        return(TRUE);    }        ip_free(pkt);        return(FALSE);
  119.     /* what a crock. check if the packet was sent to an ip        broadcast address. If it was, don't send a destination        unreachable.    */    if((p_ip->dst_inaddr == 0xffffffffL)) /* Physical cable broadcast addr*/
  120.     {        ip_free(pkt);        return(FALSE);    }    /* send destination unreachable */
  121.     icmp_dstun(p_ip->src_inaddr,p_ip,ICMP_DSTPORT);
  122.     ip_free(pkt);    return(FALSE);}
  123.  
  124. /* This routine drops a UDP packet from the udp-port, if nobody */
  125. /* fetched the data within the UDP_KEEPPKT timeout                 */
  126.  
  127. void udp_droppacket(TIMER tm)
  128. {
  129. UDP_CTL *p_udpctl;
  130.     p_udpctl = udp_list;
  131.     while(p_udpctl)
  132.     {
  133.         if(p_udpctl->udp_tm == tm)
  134.         {
  135.             if(p_udpctl->pkt)
  136.             {
  137. #ifdef DEBUGDROP
  138. printf("UDP: dropping packet from %8lx.%u\n",p_udpctl->fhost,p_udpctl->fgn_port);
  139. #endif
  140.                 p_udpctl->fhost = 0L;
  141.                 p_udpctl->fgn_port = 0;
  142.                 p_udpctl->data_len = 0;
  143.                 p_udpctl->data = NULL;
  144.                 ip_free(p_udpctl->pkt);
  145.                 p_udpctl->pkt = NULL;
  146.                 p_udpctl->udp_err = UDP_MISS;            }
  147.         }
  148.         p_udpctl = p_udpctl->next;
  149.     }
  150.     return;
  151. }
  152.  
  153.  
  154. UDP_CTL *udp_getctl(u_short udp)
  155. {
  156.  
  157.     if(udp >= udp_tablen) return(NULL);
  158.     return(udp_tab[udp]);
  159. }
  160.  
  161.  
  162.  
  163. /* This routine drops a udp packet from its port */
  164.  
  165. int udp_free(u_short udp)
  166. {
  167. UDP_CTL *p_udpctl;
  168.     if(udp >= udp_tablen) return(-1);
  169.     p_udpctl = udp_tab[udp];
  170.     if(p_udpctl && p_udpctl->pkt)
  171.     {
  172.         p_udpctl->fhost = 0L;
  173.         p_udpctl->fgn_port = 0;
  174.         p_udpctl->data_len = 0;
  175.         p_udpctl->data = NULL;
  176.         tm_stop(p_udpctl->udp_tm);
  177.         ip_free(p_udpctl->pkt);
  178.         p_udpctl->pkt = NULL;
  179.         p_udpctl->udp_err = UDP_OK;
  180.         return(udp);    }
  181.     return(-1);
  182. }
  183.  
  184.  
  185. /* This routine handles incoming UDP destination unreachable packets.    They're handed to it by the internet layer. It demultiplexes    the incoming packet based on the local port and upcalls the    appropriate routine. */int udp_du_handler(IP *p_ip){register UDP *p_udp;register UDP_CTL *p_udpctl;
  186. Bconws("UDP destunreachable\r");    p_udp = udp_head(p_ip);    for(p_udpctl = udp_list; p_udpctl; p_udpctl = p_udpctl->next)
  187.     {        if(p_udpctl->lcl_port && (p_udpctl->lcl_port != p_udp->src_port))            continue;
  188.         p_udpctl->udp_err = UDP_NORECV;        if(p_udpctl->upcall)            p_udpctl->upcall(p_udpctl->handle,NULL,UDP_NORECV);        return(TRUE);    }
  189.     return(FALSE);}
  190.  
  191.  
  192. /* This routine removes a udp-port from the udp connections list    */
  193. /* and frees all related memory                                     */
  194.  
  195. int udp_close(u_short udp)
  196. {UDP_CTL *p_udpctl;
  197. UDP_CTL **pp_udpctl;    if (udp >= udp_tablen) return(-1);
  198.     pp_udpctl = &udp_list;
  199.     p_udpctl = udp_list;
  200.     while(p_udpctl)
  201.     {
  202.         if(p_udpctl == udp_tab[udp])    /* found */
  203.         {
  204. #ifdef DEBUGCLS
  205. printf("UDP: close port %u\n",p_udpctl->lcl_port);
  206. #endif
  207.             *pp_udpctl = p_udpctl->next;    /* unlink from list */
  208.             if(p_udpctl->pkt)
  209.             {
  210.                 tm_stop(p_udpctl->udp_tm);
  211.                 ip_free(p_udpctl->pkt);
  212.             }
  213.             buf_free(udp_buffers,(char *)p_udpctl);
  214.             udp_tab[udp] = NULL;
  215.             return(udp);        }        pp_udpctl = &(p_udpctl->next);        p_udpctl = p_udpctl->next;    }    return(0);}
  216.     
  217.     int udp_open(u_short lcl_port,UDP_UPCALL upcall){int i;UDP_CTL *p_udpctl;
  218.  
  219.     if(!lcl_port)
  220.         lcl_port = udp_newport();
  221. #ifdef DEBUGOPN
  222. printf("UDP: open port %u\n",lcl_port);
  223. #endif    
  224.     for(p_udpctl = udp_list; p_udpctl; p_udpctl = p_udpctl->next)
  225.     {        if(p_udpctl->lcl_port == lcl_port)
  226.         {#ifdef DEBUGOPN
  227. printf("UDP: port %u already in use\n",lcl_port);
  228. #endif    
  229.             return -1;        }    }
  230.     
  231.     for(i=0; i < udp_tablen; i++)
  232.         if(!udp_tab[i]) break;
  233.     if(i == udp_tablen)
  234.     {
  235. #ifdef DEBUGOPN
  236. printf("UDP: port table full\n");
  237. #endif    
  238.         return(-1);
  239.     }
  240.     p_udpctl = (UDP_CTL *)buf_alloc(udp_buffers,sizeof(UDP_CTL));    if(!p_udpctl)
  241.     {#ifdef DEBUGOPN
  242. printf("UDP: out of buffers\n");
  243. #endif    
  244.         return(-1);    }    udp_tab[i] = p_udpctl;
  245.     p_udpctl->next = udp_list;
  246.     udp_list = p_udpctl;
  247.     
  248.         p_udpctl->lcl_port = lcl_port;        /* fill in connection info */    p_udpctl->fgn_port = 0;    p_udpctl->fhost = 0L;    p_udpctl->upcall = upcall;
  249.     p_udpctl->pkt = NULL;
  250.     p_udpctl->data_len = 0;    p_udpctl->data = NULL;
  251.     p_udpctl->udp_err = UDP_OK;        return(i);}
  252. int udp_write(u_short udp, char *data, u_short len, INADDR fhost, u_short port){register UDP    *p_udp;TCP_PSEUDO          udp_ph;PACKET             *pkt;
  253. UDP_CTL            *p_udpctl;
  254. register int      udplen;
  255. u_short          csum;
  256. int              ret;
  257.     if(udp >= udp_tablen || !udp_tab[udp] ||
  258.        !fhost || !port || !data)
  259.         return(-1);
  260.         
  261.     p_udpctl = udp_tab[udp];
  262.     if(p_udpctl->udp_err == UDP_NORECV) return(-1);
  263.  
  264.     udplen = len + (int)sizeof(UDP);    pkt = ip_alloc(udplen,0);
  265.     if(!pkt) return(-1);
  266.     p_udp = (UDP *)ip_data(pkt);
  267.     p_udp->length = udplen;    p_udp->src_port = p_udpctl->lcl_port;    p_udp->dst_port = port;    p_udp->chksum = 0;
  268.     p_udpctl->fgn_port = port;    p_udpctl->fhost = fhost;    udp_ph.src = ip_myaddr();    udp_ph.dst = fhost;    udp_ph.protocol = IP_UDP;    udp_ph.length = udplen;
  269.     
  270.     if(len) memcpy(udp_data(p_udp),data,len);        /* copy data */
  271.     
  272.     csum = ~chksum((u_short *)&udp_ph,(int)sizeof(TCP_PSEUDO),0);
  273.     p_udp->chksum = chksum((u_short *)p_udp,udp_ph.length,csum);
  274.  
  275.     udp_counts[1]++;
  276.     ret = ip_send(IP_UDP,pkt,udp_ph.length,fhost);
  277.  
  278. #ifdef DEBUGWR
  279. printf("UDP: pkt[%d] %u to   %08lx.%u\n",udp_ph.length,p_udpctl->lcl_port,fhost,port);
  280. if(ret < 0) printf("ip_send: network error %d\n",ret);
  281. #endif
  282.     ip_free(pkt);
  283.     return(len);
  284. }
  285.  
  286.  
  287. u_short udp_newport(void)
  288. {
  289. static u_short udp_actport = 0;
  290.  
  291.     if(!udp_actport)
  292.     {
  293.         udp_actport = (u_short)clock();
  294.     }
  295.     else
  296.         udp_actport++;
  297.     if(udp_actport < 1200)
  298.         udp_actport += 1200;
  299.     return(udp_actport);
  300. }